// Checkr
// ======
//
// VERSION HISTORY
// ===============
// v1.0 - Initial Release
// v1.1 - Added Taskbar Notifier/Removed Balloon popup
//      - Changed notifications so that only when new messages
//        arrive a notification pops up.
//      - Added "Tell Me Again" to context menu
//      - Added skins for Taskbar Notifier (added "/skins" directory)
//      - Changed directory that profiles are stored in to "/profiles"
//      - Added ability to change the checking interval (added config.cfg file)
// v1.2 - Changed notifications so that only when new errors occur a 
//        notification pops up.
//      - Changed Options dialog GUI.
//      - Changed About dialog GUI.
//      - Changed Add and Edit dialog GUI's.
//      - Removed minimize/maximize before hiding/showing. Looks smoother.
//      - Changed Edit dialog GUI button from "Edit" to "Save"
//      - Added SkinManager and SkinChooser
//      - Added BackgroundWorker so that checking is now multithreaded.
// v1.2.1 - Fixed crashing bug when checking mail.
//
// OTHER INFO
// ==========
// Copyright Gilbert Pellegrom 2008
// Release under Creative Commons: Attribution - NoDerivs 2.0 England and Wales License
// http://www.gilbertpellegrom.co.uk/checkr

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.Win32;
using System.Threading;
using Joshi.Utils.Imap;

namespace Checkr
{
    public partial class Form1 : Form
    {
        public static string VERSION = "v1.2.1";
        public static string BASE_DIR = Application.StartupPath;
        public string CONFIG_FILE = BASE_DIR + "/config.cfg";
        private RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
        private ArrayList profiles;
        private ProfileManager profileMan;
        private SkinManager skinMan;
        private ArrayList messages = new ArrayList();
        private ArrayList errors = new ArrayList();
        private ArrayList lastMessages = new ArrayList();
        private ArrayList lastErrors = new ArrayList();
        private int lastTotal = 0;
        private int lastErrorTotal = 0;
        int unseen = 0;
        int unread = 0;
        int total = 0;
        int errorTotal = 0;
        int percent = 0;

        public Form1()
        {
            InitializeComponent();

            this.Closing += new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
            updateLabels("CheckR " + VERSION);

            profileMan = new ProfileManager();
            listProfiles();

            //Update run at startup checkbox
            if (rkApp.GetValue("Checkr") == null)
            {
                checkBox1.Checked = false;
            }
            else
            {
                checkBox1.Checked = true;
            }

            //Taskbar notifier
            skinMan = new SkinManager(taskbarNotifier);
            skinMan.loadSkins();

            //Load Config File
            try
            {
                StreamReader read = File.OpenText(CONFIG_FILE);
                string interval = read.ReadLine();
                string skin = read.ReadLine();
                read.Close();
                timer1.Interval = Convert.ToInt32(interval);
                trackBar1.Value = (timer1.Interval / 1000);
                label1.Text = (timer1.Interval/1000) + " secs";
                skinMan.loadSkin(skin.Trim());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }

        #region ///Events /////////////////////
        private void timerTick(object sender, EventArgs e)
        {
            goCheckr();
        }

        private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //Save Check Interval
            try
            {
                StreamWriter writer = new StreamWriter(CONFIG_FILE);
                writer.WriteLine((trackBar1.Value * 1000));
                writer.WriteLine(skinMan.currentSkin); //From SkinManager
                writer.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

            this.form1_Hide(sender, e);
            e.Cancel = true;
        }


        private void button1_Click(object sender, EventArgs e)
        {
            this.goCheckr();
        }

        private void form1_Hide(object sender, EventArgs e)
        {
            Hide();
            this.ShowInTaskbar = false;
        }

        private void checkEmailsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.goCheckr();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            listProfiles();
            Show();
            this.ShowInTaskbar = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Form2 addProfileForm = new Form2();
            addProfileForm.frm1 = this;
            addProfileForm.ShowDialog();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure you want to delete this profile?", "Delete Profile", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                if (listBox1.SelectedItem != null)
                {
                    profiles.Remove(listBox1.SelectedItem);
                    profileMan.deleteProfile((string)listBox1.SelectedItem);
                    listProfiles();
                }
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm aboutForm = new AboutForm();
            aboutForm.ShowDialog();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                // Add the value in the registry so that the application runs at startup
                rkApp.SetValue("Checkr", Application.ExecutablePath.ToString());
            }
            else
            {
                // Remove the value from the registry so that the application doesn't start
                rkApp.DeleteValue("Checkr", false);
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            //Save Check Interval
            try
            {
                StreamWriter writer = new StreamWriter(CONFIG_FILE);
                writer.WriteLine((trackBar1.Value * 1000));
                writer.WriteLine(skinMan.currentSkin); //From SkinManager
                writer.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

            this.Close();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                Form3 editProfileForm = new Form3((string)listBox1.SelectedItem);
                editProfileForm.frm1 = this;
                editProfileForm.ShowDialog();
            }
        }

        private void tellMeAgainToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tellMeAgain(sender, e);
        }

        private void TitleClick(object sender, EventArgs e)
        {
        }
        private void ContentClick(object sender, EventArgs e)
        {
            showFullMessage(sender, e);
        }
        private void CloseClick(object sender, EventArgs e)
        {
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            label1.Text = trackBar1.Value + " secs";
            timer1.Interval = trackBar1.Value * 1000;
            //See button4_Click for writing to file
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("www.gilbertpellegrom.co.uk/checkr");
        }

        private void button6_Click(object sender, EventArgs e)
        {
            SkinChooser skinChooser = new SkinChooser(skinMan);
            skinChooser.ShowDialog();
        }
        #endregion

        public void listProfiles()
        {
            profiles = profileMan.loadProfiles();
            listBox1.Items.Clear();
            foreach (Profile temp in profiles)
            {
                if (!listBox1.Items.Contains(temp.username + "@" + temp.server))
                {
                    listBox1.Items.Add(temp.username + "@" + temp.server);
                }
            }
        }

        private void updateLabels(string what){
            toolStripStatusLabel1.Text = what;
            notifyIcon1.Text = what;
            statusStrip1.Update();
        }

        public void tellMeAgain(object sender, EventArgs e)
        {
            if (lastErrors.Count > 0)
            {
                string msg = "";
                foreach (String tempMsg in lastErrors)
                {
                    if (msg.Split('\n').Length > 2)
                    {
                        msg += (lastErrors.Count - 2) + " more lines... (Click for full message)";
                        break;
                    }
                    else
                    {
                        msg += tempMsg + "\n";
                    }
                }
                taskbarNotifier.Show("Error", msg, 500, 5000, 500);
            }
            if (lastMessages.Count > 0)
            {
                string msg = "";
                foreach (String tempMsg in lastMessages)
                {
                    if (msg.Split('\n').Length > 2)
                    {
                        msg += (lastMessages.Count - 2) + " more lines... (Click for full message)";
                        break;
                    }
                    else
                    {
                        msg += tempMsg + "\n";
                    }
                }
                taskbarNotifier.Show(lastTotal + " New Messages", msg, 500, 5000, 500);
            }
        }

        public void showFullMessage(object sender, EventArgs e)
        {
            string msg = "";
            if (lastErrors.Count > 0)
            {
                msg += "Errors:\n";
                foreach (String tempMsg in lastErrors)
                {
                    msg += tempMsg + "\n";
                }
                msg += "\n";
            }

            if (lastMessages.Count > 0)
            {
                msg += "Messages:\n";
                foreach (String tempMsg in lastMessages)
                {
                    msg += tempMsg + "\n";
                }
            }

            if(msg != "")
                MessageBox.Show(msg, "Checkr - Full Status");
        }

        public void goCheckr()
        {
            this.notifyIcon1.Icon = new Icon(GetType(), "faviconWorking.ico");

            toolStripStatusLabel1.Visible = false;
            toolStripProgressBar1.Visible = true;
            toolStripProgressBar1.Value = 0;
            updateLabels("Checking...");

            messages = new ArrayList();
            errors = new ArrayList();
            unseen = 0;
            unread = 0;
            total = 0;
            errorTotal = 0;
            percent = 0;

            try
            {
                backgroundWorker1.RunWorkerAsync();
            }
            catch(Exception exc)
            {
                Console.WriteLine(exc.Message);
            }
        }

        public void doWork(object sender, DoWorkEventArgs e)
        {
            StreamWriter writer;

            foreach (Profile prof in profiles)
            {
                try
                {
                    backgroundWorker1.ReportProgress(20);

                    if (prof.type == "POP")
                    {
                        Pop3MailClient DemoClient = new Pop3MailClient(prof.server, Convert.ToInt32(prof.port), prof.ssl, prof.username, prof.password);
                        DemoClient.IsAutoReconnect = true;

                        //remove the following line if no tracing is needed
                        //DemoClient.Trace += new Checkr.TraceHandler(Console.WriteLine);
                        DemoClient.ReadTimeout = 60000; //give pop server 60 seconds to answer
                        backgroundWorker1.ReportProgress(20);

                        //establish connection
                        DemoClient.Connect();
                        backgroundWorker1.ReportProgress(20);

                        //get mailbox statistics
                        int NumberOfMails, MailboxSize;
                        DemoClient.GetMailboxStats(out NumberOfMails, out MailboxSize);

                        string newSTAT = NumberOfMails + " " + MailboxSize;
                        try
                        {
                            if (!File.Exists(BASE_DIR + "/profiles/" + prof.username + "@" + prof.server + ".dat"))
                            {
                                writer = new StreamWriter(BASE_DIR + "/profiles/" + prof.username + "@" + prof.server + ".dat");
                                writer.WriteLine(newSTAT);
                                writer.Close();
                            }
                        }
                        catch
                        {
                            errors.Add("Error writing file " + BASE_DIR + "/profiles/" + prof.username + "@" + prof.server + ".dat");
                            errorTotal++;
                        }

                        StreamReader reader = new StreamReader(BASE_DIR + "/profiles/" + prof.username + "@" + prof.server + ".dat");
                        string oldSTAT = reader.ReadLine();
                        reader.Close();
                        string[] oldNum = oldSTAT.Trim().Split(' ');
                        string[] newNum = newSTAT.Trim().Split(' ');

                        unread = Convert.ToInt32(newNum[0]) - Convert.ToInt32(oldNum[0]);
                        total += unread;
                        if (unread == 1)
                        {
                            messages.Add(prof.server + ": You have " + unread + " new message");
                        }
                        else if (unread > 1)
                        {
                            messages.Add(prof.server + ": You have " + unread + " new messages");
                        }
                        else
                        { }

                        //Update
                        writer = new StreamWriter(BASE_DIR + "/profiles/" + prof.username + "@" + prof.server + ".dat");
                        writer.WriteLine(newSTAT);
                        writer.Close();

                        //close connection
                        DemoClient.Disconnect();
                    }
                    else if (prof.type == "IMAP")
                    {
                        Imap imap = new Imap();
                        imap.Login(prof.server, Convert.ToUInt16(prof.port), prof.username, prof.password, prof.ssl);
                        backgroundWorker1.ReportProgress(20);
                        imap.SelectFolder("INBOX");
                        unseen = imap.GetUnseen();
                        total += unseen;
                        backgroundWorker1.ReportProgress(20);
                        if (unseen == 1)
                        {
                            messages.Add(prof.server + ": You have " + unseen + " new message");
                        }
                        else if (unseen > 1)
                        {
                            messages.Add(prof.server + ": You have " + unseen + " new messages");
                        }
                        else
                        { }
                        imap.LogOut();
                    }
                    else
                    {
                        //well nothing really
                    }

                }
                catch (Exception ex)
                {
                    Console.WriteLine();
                    Console.WriteLine("Run Time Error Occured:");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                    backgroundWorker1.ReportProgress(-1);
                    errors.Add("Could not connect to " + prof.server);
                    errorTotal++;
                }
            }//foreach        
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage > 0)
            {
                percent += e.ProgressPercentage / profiles.Count;
                toolStripProgressBar1.Value = percent;
            }
            else
            {
                updateLabels("Error: Could not connect");
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            toolStripProgressBar1.Visible = false;
            toolStripStatusLabel1.Visible = true;

            //Display Errors
            if (errors.Count > 0 && lastErrorTotal != errorTotal)
            {
                string msg = "";
                foreach (String tempMsg in errors)
                {
                    if (msg.Split('\n').Length > 2)
                    {
                        msg += (errors.Count - 2) + " more lines... (Click for full message)";
                        break;
                    }
                    else
                    {
                        msg += tempMsg + "\n";
                    }
                }
                taskbarNotifier.Show("Error", msg, 500, 3000, 500);
            }

            //Display new messages
            if (messages.Count > 0 && lastTotal != total)
            {
                string msg = "";
                foreach (String tempMsg in messages)
                {
                    if (msg.Split('\n').Length > 2)
                    {
                        msg += (messages.Count - 2) + " more lines... (Click for full message)";
                        break;
                    }
                    else
                    {
                        msg += tempMsg + "\n";
                    }
                }
                taskbarNotifier.Show(total + " New Messages", msg, 500, 5000, 500);
            }

            //Update Labels
            if (total < 1)
            {
                updateLabels("You have no new messages");
                this.notifyIcon1.Icon = new Icon(GetType(), "favicon.ico");
            }
            else if (total == 1)
            {
                updateLabels("You have " + total + " new message");
                this.notifyIcon1.Icon = new Icon(GetType(), "faviconNew.ico");
            }
            else
            {
                updateLabels("You have " + total + " new messages");
                this.notifyIcon1.Icon = new Icon(GetType(), "faviconNew.ico");
            }

            //Update last total so same message doesn't keep popping up
            lastTotal = total;
            lastErrorTotal = errorTotal;
            //For Tell Me Again
            lastMessages = messages;
            lastErrors = errors;
        }
    }
}